home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc™ Source Code / Storage / Bento / CMDoc.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-28  |  43.3 KB  |  1,626 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        CMDoc.cpp
  3.  
  4.     Contains:    Implementation for CMDoc class.
  5.  
  6.     Owned by:    Vincent Lo
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <7>     8/19/96    DH        1376276:OpenDoc corrupts document when it
  13.                                     runs out of disk space creating draft. Made
  14.                                     more exceptions fatal container errors.
  15.                                     Changed writing out new draft version list
  16.                                     to work around bug with old space being
  17.                                     reused too soon. Made numerous values temps
  18.                                     so their useCount is properly set.
  19.          <6>     7/25/96    DH        Fixed NewCMDraft methods to check the
  20.                                     somClassReference allocation and throw if
  21.                                     null (No bug #, approved by Bern).
  22.          <5>      6/6/96    jpa        T10020: Avoid compiler warning (and ODIText
  23.                                     leak!) in CMDocumentGetName.
  24.          <4>     5/24/96    jpa        1246074: SOM_CATCH --> SOM_TRY..SOM_ENDTRY
  25.          <2>     3/15/96    DM        1295410: create list iterators on stack
  26.                                     (avoid mem thrash during purge)
  27.  
  28.     To Do:
  29.     In Progress:
  30.         
  31. */
  32.  
  33. #define CMDocument_Class_Source
  34. #define VARIABLE_MACROS
  35. #include <CMDoc.xih>
  36.  
  37. #ifndef SOM_ODContainer_xh
  38. #include <ODCtr.xh>
  39. #endif
  40.  
  41. #ifndef SOM_ODStorageUnit_xh
  42. #include <StorageU.xh>
  43. #endif
  44.  
  45. #ifndef _EXCEPT_
  46. #include "Except.h"
  47. #endif
  48.  
  49. #ifndef _TEMPOBJ_
  50. #include "TempObj.h"
  51. #endif
  52.  
  53. #ifndef _FLIPEND_
  54. #include "FlipEnd.h"
  55. #endif
  56.  
  57. #ifndef SOM_ODEmbeddedContainer_xh
  58. #include <EmbedCtr.xh>
  59. #endif
  60.  
  61. #ifndef SOM_CMDraft_xh
  62. #include <CMDraft.xh>
  63. #endif
  64.  
  65. #ifndef SOM_ODSession_xh
  66. #include <ODSessn.xh>
  67. #endif
  68.  
  69. #ifndef __STRING__
  70. #include <string.h>        // For strlen, strcpy....
  71. #endif
  72.  
  73. #ifndef _INDHDR_
  74. #include "IndHdr.h"            // For Embedded Property and Type names
  75. #endif
  76.  
  77. #ifndef _CMCTR_
  78. #include "CMCtr.xh"            // Just for getting fContainer
  79. #endif
  80.  
  81. #ifndef _DOCPRIV_
  82. #include "DocPriv.h"
  83. #endif
  84.  
  85. #ifndef _ISOSTR_
  86. #include "ISOStr.h"
  87. #endif
  88.  
  89. #ifndef SOM_Module_OpenDoc_StdProps_defined
  90. #include <StdProps.xh>
  91. #endif
  92.  
  93. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  94. #include <StdTypes.xh>
  95. #endif
  96.  
  97. #ifndef _ODMEMORY_
  98. #include "ODMemory.h"
  99. #endif
  100.  
  101. #ifndef _ODNEW_
  102. #include "ODNew.h"
  103. #endif
  104.  
  105. #ifndef _BENTODEF_
  106. #include "BentoDef.h"
  107. #endif
  108.  
  109. #ifndef _ODDEBUG_
  110. #include <ODDebug.h>
  111. #endif
  112.  
  113. #ifndef _ITEXT_
  114. #include <IText.h>
  115. #endif
  116.  
  117. #ifndef _UTILERRS_
  118. #include "UtilErrs.h"
  119. #endif
  120.  
  121. #ifndef __TIME_H__
  122. #include <Time.h>
  123. #endif
  124.  
  125. #ifndef _SESSHDR_
  126. #include "SessHdr.h"
  127. #endif
  128.  
  129. #ifndef _BENTOSUPPRESS_
  130. #include "BentoSuppress.h"
  131. #endif
  132.  
  133. #pragma segment CMDocument
  134.  
  135. //==============================================================================
  136. // Constants
  137. //==============================================================================
  138.  
  139. // Private ISO Strings
  140. const     ODPropertyName    kODDocumentProperties    = "+//ISO 9070/ANSI::113722::US::CI LABS::OpenDoc:Bento Container Suite:Property:DocumentProperties";
  141. const    ODValueType        kODVersionList             = "+//ISO 9070/ANSI::113722::US::CI LABS::OpenDoc:Bento Container Suite:Type:CMVersionList";
  142.  
  143. // For debugging
  144.  
  145. #if ODDebug
  146. // #define ODDebug_Drafts 1
  147. // #define ODDebug_DebugRefCount    1
  148. #endif
  149.  
  150. //==============================================================================
  151. // Function Prototype
  152. //==============================================================================
  153.  
  154. static CMDraft* NewCMDraft(ODMemoryHeapID heapID);
  155. static CMObject AcquireDocumentPropertiesObject(CMContainer container);
  156.  
  157. // The following two functions need to be filled in when we are moving to a 
  158. // real multithread system.
  159.  
  160. #define EnableInterrupt()
  161. #define DisableInterrupt()
  162.  
  163.  
  164. // For debugging
  165.  
  166. #ifdef DebugStorage
  167.  
  168. #define MyDebugStr(s) do {somPrintf(s);} while (0)
  169. #define MyDebug1Str(f,p1) do {somPrintf(f, p1);} while (0)
  170. #define MyDebug2Str(f,p1,p2) do {somPrintf(f, p1, p2);} while (0)
  171. #define MyDebug3Str(f,p1,p2,p3) do {somPrintf(f, p1, p2,p3);} while (0)
  172.  
  173. #else
  174.  
  175. #define MyDebugStr(s)
  176. #define MyDebug1Str(f,p1)
  177. #define MyDebug2Str(f,p1,p2)
  178. #define MyDebug3Str(f,p1,p2,p3)
  179.  
  180. #endif
  181.  
  182. #if ODDebug_Drafts
  183.  
  184. #ifndef _MEMDEBG_
  185. #include <MemDebg.h>
  186. #endif
  187.  
  188. static void PrintDrafts(Environment* ev, DraftList* drafts, char* string);
  189. static void PrintHeapInfo();
  190. #endif
  191.  
  192.  
  193. //==============================================================================
  194. // CMDocument
  195. //==============================================================================
  196.  
  197. //------------------------------------------------------------------------------
  198. // CMDocument: GetCMVersionList
  199. //------------------------------------------------------------------------------
  200.  
  201. SOM_Scope CMValue  SOMLINK CMDocumentGetCMVersionList(CMDocument *somSelf, Environment *ev)
  202. {
  203.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  204.     CMDocumentMethodDebug("CMDocument","CMDocumentGetCMVersionList");
  205.     
  206.     // The CMValue returned by this method must be realeased by calling CMReleaseValue().
  207.     // You can do this automatically by using the TempCMValue class.
  208.  
  209.     SOM_TRY
  210.     
  211.     CMContainer cmContainer = _fContainer->GetCMContainer(ev);
  212.     ODSessionMustHaveCMAllocReserve(cmContainer);
  213.     
  214.     CMProperty        versionListProp;
  215.     CMObject        versionListObj;
  216.     
  217.     if ((versionListProp = CMRegisterProperty(cmContainer, kODPropVersionList)) == kODNULL)
  218.         THROW(kODErrBentoInvalidProperty);
  219.         
  220.     versionListObj = CMGetNextObjectWithProperty(cmContainer, kODNULL, versionListProp);
  221.     
  222.     TempCMValue versionList = kODNULL;
  223.     if ( versionListObj )
  224.         versionList = CMGetNextValue(versionListObj, versionListProp, kODNULL);
  225.  
  226.     ODSessionRestoreCMAllocReserve(cmContainer);
  227.     
  228.     return versionList.DontRelease();
  229.  
  230.     SOM_CATCH_ALL
  231.     SOM_ENDTRY
  232.     return kODNULL;
  233. }
  234.  
  235. //------------------------------------------------------------------------------
  236. // CMDocument: AcquireDraftGut
  237. //------------------------------------------------------------------------------
  238.  
  239. SOM_Scope CMDraft*  SOMLINK CMDocumentAcquireDraftGut(CMDocument *somSelf, Environment *ev,
  240.         VersionList* versionList,
  241.         ODDraftPermissions perms,
  242.         ODDraftID id,
  243.         CMDraft* draft,
  244.         ODPositionCode posCode,
  245.         ODBoolean release)
  246. {
  247.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  248.     CMDocumentMethodDebug("CMDocument","CMDocumentAcquireDraftGut");
  249.  
  250.     SOM_TRY
  251.  
  252. #if ODDebug_Drafts
  253.     somPrintf("**** Entering AcquireDraftGut: id %d draft %x posCode %d release %d\n", id, draft, posCode, release);
  254.     PrintDrafts(ev, _fDrafts, "**** Entering AcquireDraftGut");
  255.     somSelf->GetVersionList(ev)->Print(">>> Entering AcquireDraftGut");
  256. #endif
  257.  
  258.     CMDraft*                fromDraft = (CMDraft*) draft;
  259.     CMDraft*                newDraft = kODNULL;    
  260.     ODDraftID                latestDraftID;
  261.     ODDraftID                fromDraftID;
  262.     ODDraftID                prevDraftID;
  263.     ODDraftID                nextDraftID;
  264.  
  265.     if (id != 0) {
  266.         if ((newDraft = _fDrafts->Get(id)) != kODNULL) {
  267.             if ((perms == kODDPReadOnly) ||
  268.                 (newDraft->GetPermissions(ev) == kODDPExclusiveWrite)) {
  269.                 newDraft->Acquire(ev);
  270.                 MyDebugStr("**** AcquireDraft: Acquire only.\n");
  271.             }
  272.             else
  273.                 THROW(kODErrInvalidPermissions);
  274.         }
  275.         else if ((newDraft = _fReleasedDrafts->Get(id)) != kODNULL) {
  276.             if (perms == kODDPExclusiveWrite) {
  277.                 if (newDraft->GetPermissions(ev) == kODDPReadOnly) {
  278.                         latestDraftID = versionList->GetLatestDraftID();
  279.                         if (versionList->IsAbove(latestDraftID, id) != kODFalse)
  280.                             THROW(kODErrInvalidPermissions);
  281.                         MyDebugStr("**** AcquireDraft: From ReadOnly to ExclusiveWrite.\n");
  282.                 }
  283.             }
  284.             newDraft->Reinitialize(ev, perms);
  285.             _fReleasedDrafts->Remove(id);
  286.             _fDrafts->Add(id, newDraft);
  287.             newDraft->Acquire(ev);
  288.             MyDebugStr("**** AcquireDraft: Back from the _fReleasedDrafts pile.\n");
  289.         }
  290.         else {                
  291.             newDraft = NewCMDraft(somSelf->GetHeap(ev));
  292.             newDraft->InitDraft(ev, somSelf, id, perms);
  293.             
  294.             _fDrafts->Add(id, newDraft);
  295.     
  296.             MyDebug3Str("**** id %d draft %x perms %d\n", id, newDraft, newDraft->GetPermissions(ev));
  297.         }    
  298.     }
  299.     else {
  300.         if ((posCode != kODPosTop) && (fromDraft == kODNULL)) {
  301.             THROW(kODErrInvalidDraftID);
  302.         }
  303.         switch (posCode) {
  304.             case kODPosTop:
  305.                 if (fromDraft != kODNULL)
  306.                     THROW(kODErrInvalidDraftID);
  307.                 nextDraftID = versionList->GetLatestDraftID();
  308.                 newDraft = somSelf->AcquireDraftGut(ev, versionList,
  309.                                     perms,
  310.                                     nextDraftID,
  311.                                     kODNULL,
  312.                                     kODPosUndefined,
  313.                                     kODFalse);
  314.             break;
  315.             case kODPosSame:
  316.                 if (fromDraft->GetPermissions(ev) == perms) {
  317.                     if (release == kODFalse)
  318.                         fromDraft->Acquire(ev);
  319.                     newDraft = fromDraft;
  320.                 }
  321.                 else {
  322.                     if (fromDraft->GetRefCount(ev) != 1)
  323.                         THROW(kODErrRefCountNotEqualOne);
  324.                     if (release == kODFalse)
  325.                         THROW(kODErrCannotChangePermissions);
  326.                     fromDraftID = fromDraft->GetID(ev);
  327.                     fromDraft->Release(ev);
  328.                     newDraft = somSelf->AcquireDraftGut(ev, versionList,
  329.                                                 perms,
  330.                                                 fromDraftID,
  331.                                                 kODNULL,
  332.                                                 kODPosUndefined,
  333.                                                 kODFalse);
  334.                 }
  335.             break;
  336.             case kODPosFirstBelow:
  337.             case kODPosLastBelow:
  338.                 fromDraftID = fromDraft->GetID(ev);
  339.                 prevDraftID = versionList->GetPreviousDraftID(fromDraftID);
  340.                 if (release != kODFalse)
  341.                     fromDraft->Release(ev);
  342.                 newDraft = somSelf->AcquireDraftGut(ev, versionList,
  343.                                             perms,
  344.                                             prevDraftID,
  345.                                             kODNULL,
  346.                                             kODPosUndefined,
  347.                                             kODFalse);
  348.             break;
  349.             case kODPosFirstAbove:
  350.             case kODPosLastAbove:
  351.                 fromDraftID = fromDraft->GetID(ev);
  352.                 nextDraftID = versionList->GetNextDraftID(fromDraftID);
  353.                 if (release != kODFalse)
  354.                     fromDraft->Release(ev);
  355.                 newDraft = somSelf->AcquireDraftGut(ev, versionList,
  356.                                             perms,
  357.                                             nextDraftID,
  358.                                             kODNULL,
  359.                                             kODPosUndefined,
  360.                                             kODFalse);
  361.                 break;
  362.             case kODPosUndefined:
  363.             case kODPosAll:
  364.             case kODPosFirstSib:
  365.             case kODPosLastSib:
  366.             case kODPosNextSib:
  367.             case kODPosPrevSib:
  368.             default:
  369.                 THROW(kODErrUnsupportedPosCode);
  370.             break;
  371.         }
  372.     }
  373.     
  374. #if ODDebug_Drafts
  375.     PrintDrafts(ev, _fDrafts, "**** Exiting AcquireDraftGut");
  376.     somSelf->GetVersionList(ev)->Print(">>> Exiting AcquireDraftGut");
  377. #endif
  378.  
  379.     return newDraft;
  380.  
  381.     SOM_CATCH_ALL
  382.     SOM_ENDTRY
  383.     return kODNULL;
  384. }
  385.  
  386. //------------------------------------------------------------------------------
  387. // CMDocument: ~CMDocument
  388. //------------------------------------------------------------------------------
  389.  
  390. SOM_Scope void  SOMLINK CMDocumentsomUninit(CMDocument *somSelf)
  391. {
  392.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  393.     CMDocumentMethodDebug("CMDocument","CMDocumentsomUninit");
  394.  
  395.     TRY
  396.     
  397.     Environment*    ev = somGetGlobalEnvironment();
  398.     
  399.     DraftListIterator iter(_fDrafts);
  400.     iter.Initialize();
  401.     
  402.     DraftListIterator releasedDraftsIter(_fReleasedDrafts);
  403.     releasedDraftsIter.Initialize();
  404.     
  405.     CMDraft*            draft;
  406.  
  407. #if ODDebug_DebugRefCount
  408.     if (somSelf->GetRefCount(ev) != 0)
  409.         DebugStr("\pRefCount of Document is not 0 at uninit.");
  410.     somPrintf("~CMDocument %x RefCount %d\n", somSelf, somSelf->GetRefCount(ev));
  411. #endif
  412.  
  413.     draft = iter.Last();
  414.     while (draft != kODNULL) {
  415.         delete draft;
  416.         draft = iter.Previous();
  417.     }
  418.         
  419.     draft = releasedDraftsIter.Last();
  420.     while (draft != kODNULL) {
  421.         delete draft;
  422.         draft = releasedDraftsIter.Previous();
  423.     }
  424.         
  425.     // delete iter;
  426.     // delete releasedDraftsIter;
  427.     
  428.     delete _fVersions;
  429.     delete _fDrafts;
  430.     delete _fReleasedDrafts;
  431.     
  432.     parent_somUninit(somSelf);
  433.  
  434.  
  435.     CATCH_ALL
  436.     ENDTRY
  437. }
  438.  
  439. //------------------------------------------------------------------------------
  440. // CMDocument: Purge
  441. //------------------------------------------------------------------------------
  442.  
  443. SOM_Scope ODSize  SOMLINK CMDocumentPurge(CMDocument *somSelf, Environment *ev,
  444.         ODSize size)
  445. {
  446.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  447.     CMDocumentMethodDebug("CMDocument","CMDocumentPurge");
  448.   
  449.     ODSize purgedSize = 0; ODVolatile( purgedSize );
  450.          
  451.     SOM_TRY
  452.         DraftListIterator draftList(_fDrafts);
  453.         draftList.Initialize();
  454.         CMDraft* draft = draftList.Last();
  455.         while (draft != kODNULL) {
  456.             TRY
  457.                 purgedSize += draft->Purge(ev, size-purgedSize);
  458.             CATCH_ALL
  459.             ENDTRY
  460.             draft = draftList.Previous();
  461.         }
  462.     // delete draftList;
  463.     
  464.         purgedSize += parent_Purge(somSelf, ev, size);
  465.     SOM_CATCH_ALL
  466.         WARN("Error %ld trying to purge in CMDocumentPurge",ErrorCode());
  467.         SetErrorCode(kODNoError);        // Eat the exception; Purge should not 
  468.                                         // propagate it because clients function
  469.                                         // fine whether memory was purged or not.
  470.     SOM_ENDTRY
  471.  
  472.     return purgedSize;
  473. }
  474.  
  475. //------------------------------------------------------------------------------
  476. // CMDocument: Acquire
  477. //------------------------------------------------------------------------------
  478.  
  479. SOM_Scope void  SOMLINK CMDocumentAcquire(CMDocument *somSelf, Environment *ev)
  480. {
  481. //  CMDocumentData *somThis = CMDocumentGetData(somSelf);
  482.     CMDocumentMethodDebug("CMDocument","CMDocumentAcquire");
  483.  
  484.     parent_Acquire(somSelf,ev);
  485. }
  486.  
  487. //------------------------------------------------------------------------------
  488. // CMDocument: Release
  489. //------------------------------------------------------------------------------
  490.  
  491. SOM_Scope void  SOMLINK CMDocumentRelease(CMDocument *somSelf, Environment *ev)
  492. {
  493.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  494.     CMDocumentMethodDebug("CMDocument","CMDocumentRelease");
  495.  
  496.     SOM_TRY
  497.     
  498. #if TestFlushContainer
  499.         if (_fContainer->GetDirtyFlag(ev) != kODFalse)
  500.             somSelf->ExternalizeVersionList(ev, kODFalse);
  501. #endif
  502.  
  503.         parent_Release(somSelf,ev);
  504.         if (somSelf->GetRefCount(ev) == 0) {
  505.             _fContainer->ReleaseDocument(ev, somSelf);
  506.         }
  507.         
  508.     SOM_CATCH_ALL
  509.         
  510.         ODError err = ErrorCode();
  511.  
  512.         WARN("Error occurred in ODDocument::Release: %d %s", err, ErrorMessage() ?ErrorMessage() :"");
  513.  
  514.         if (err == kODErrBentoErr)
  515.             SetErrorCode(kODErrUndefined);
  516.         else if (err != kODErrUndefined)
  517.             SetErrorCode(kODNoError);
  518.         
  519.     SOM_ENDTRY
  520. }
  521.  
  522. //------------------------------------------------------------------------------
  523. // CMDocument: AcquireContainer
  524. //------------------------------------------------------------------------------
  525.  
  526. SOM_Scope ODContainer*  SOMLINK CMDocumentGetContainer(CMDocument *somSelf, Environment *ev)
  527. {
  528.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  529.     CMDocumentMethodDebug("CMDocument","CMDocumentGetContainer");
  530.  
  531.     return (ODContainer*) _fContainer;
  532. }
  533.  
  534. //------------------------------------------------------------------------------
  535. // CMDocument: GetID
  536. //------------------------------------------------------------------------------
  537.  
  538. SOM_Scope ODDocumentID  SOMLINK CMDocumentGetID(CMDocument *somSelf, Environment *ev)
  539. {
  540.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  541.     CMDocumentMethodDebug("CMDocument","CMDocumentGetID");
  542.  
  543.     return _fID;
  544. }
  545.  
  546. //------------------------------------------------------------------------------
  547. // CMDocument: GetName
  548. //------------------------------------------------------------------------------
  549.  
  550. SOM_Scope ODDocumentName SOMLINK CMDocumentGetName(CMDocument *somSelf, Environment *ev)
  551. {    
  552.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  553.     CMDocumentMethodDebug("CMDocument","CMDocumentGetName");
  554.     
  555.     ODDocumentName name;
  556.     InitIText(&name);
  557.  
  558.     SOM_TRY
  559.     
  560.     CMContainer cmContainer = _fContainer->GetCMContainer(ev);
  561.     ODSessionMustHaveCMAllocReserve(cmContainer);
  562.  
  563.     CMObject    cmObject = AcquireDocumentPropertiesObject(cmContainer);
  564.     ASSERTM(cmObject, kODErrNoDocumentProperties, "No Document Properties Object.");
  565.     
  566.     CMProperty    cmProp = CMRegisterProperty(cmContainer, kODPropDocumentName);
  567.     CMType        cmType = CMRegisterType(cmContainer, kODMacIText);
  568.     CMValue        cmValue = CMUseValue(cmObject, cmProp, cmType);
  569.     
  570.     if (cmValue != kODNULL) {
  571.         ODITextFormat stdFormat;
  572.         CMReadValueData(cmValue, &stdFormat, 0, sizeof(ODITextFormat));
  573.         ODITextFormat format = ConvertODULongFromStd(stdFormat);
  574.         
  575.         if( format != kODTraditionalMacText ) {
  576.             WARN("Reading IText in unknown format %ld",format);
  577.             THROW(kODErrInvalidPersistentFormat);
  578.         }
  579.         ODULong size = CMGetValueSize(cmValue) - sizeof(ODITextFormat);
  580.         name.format = format;
  581.         SetITextBufferSize(&name,size,kODFalse);
  582.         CMReadValueData(cmValue, name.text._buffer,  sizeof(ODITextFormat), name.text._length);
  583.     } else {
  584.         SetITextStringLength(&name,0,kODFalse);
  585.         somSelf->SetName(ev, &name);
  586.     }
  587.     
  588.     ODSessionRestoreCMAllocReserve(cmContainer);
  589.         
  590.     SOM_CATCH_ALL
  591.     SOM_ENDTRY
  592.     
  593.     return name;
  594. }
  595.  
  596. //------------------------------------------------------------------------------
  597. // CMDocument: SetName
  598. //------------------------------------------------------------------------------
  599.  
  600. SOM_Scope void  SOMLINK CMDocumentSetName(CMDocument *somSelf, Environment *ev,
  601.         ODDocumentName* name)
  602. {
  603.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  604.     CMDocumentMethodDebug("CMDocument","CMDocumentSetName");
  605.  
  606.     SOM_TRY
  607.     
  608.     CMContainer    cmContainer = _fContainer->GetCMContainer(ev);
  609.     ODSessionMustHaveCMAllocReserve(cmContainer);
  610.  
  611.     CMObject    cmObject = AcquireDocumentPropertiesObject(cmContainer);
  612.     ASSERTM(cmObject, kODErrNoDocumentProperties, "No Document Properties Object.");
  613.     
  614.     CMProperty    cmProp = CMRegisterProperty(cmContainer, kODPropDocumentName);
  615.     CMType        cmType = CMRegisterType(cmContainer, kODMacIText);
  616.     CMValue        cmValue = CMUseValue(cmObject, cmProp, cmType);
  617.     if (cmValue == kODNULL) {
  618.         cmValue = CMNewValue(cmObject, cmProp, cmType);
  619.     }
  620.     ODITextFormat stdFormat = ConvertODULongToStd(name->format);
  621.     CMWriteValueData(cmValue, &stdFormat, 0, sizeof(ODITextFormat));
  622.     CMWriteValueData(cmValue, name->text._buffer,  sizeof(ODITextFormat), name->text._length);
  623.  
  624.     ODSessionRestoreCMAllocReserve(cmContainer);
  625.  
  626.     SOM_CATCH_ALL
  627.     SOM_ENDTRY
  628. }
  629.  
  630. //------------------------------------------------------------------------------
  631. // CMDocument: CollapseDrafts
  632. //------------------------------------------------------------------------------
  633.  
  634. SOM_Scope ODDocument*  SOMLINK CMDocumentCollapseDrafts(CMDocument *somSelf, Environment *ev,
  635.         ODDraft* fromDraft,
  636.         ODDraft* toDraft)
  637. {
  638.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  639.     CMDocumentMethodDebug("CMDocument","CMDocumentCollapseDrafts");
  640.  
  641.     SOM_TRY
  642.  
  643.     CMDraft*        from = (CMDraft*) fromDraft;
  644.     CMDraft*        to = (CMDraft*) toDraft; ODVolatile(to);
  645.     VersionList*    versionList = kODNULL;
  646.     ODDraftID        fromID = from->GetID(ev);
  647.     ODDraftID        toID;
  648.     ODDraftID        baseID;
  649.     // ODBoolean        releaseToDraft = kODFalse; ODVolatile(releaseToDraft);
  650.     ODBoolean         revertIt = kODFalse;
  651.     
  652.     TempODDraft     tempDraft = kODNULL; // DMc - better way to release
  653.  
  654.     versionList = somSelf->TestAndGetVersionList(ev);
  655.     ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  656.     
  657.     TRY
  658.     
  659.         baseID = versionList->GetBaseDraftID();
  660.     
  661.         if (to == kODNULL) {
  662.             toID = versionList->GetPreviousDraftID(fromID);
  663.             to = (CMDraft*) somSelf->AcquireDraft(ev, kODDPReadOnly, toID, kODNULL, kODPosUndefined, kODFalse);
  664.             // releaseToDraft = kODTrue;
  665.             tempDraft = to; // ensure it's released
  666.         }
  667.         else {
  668.             toID = to->GetID(ev);
  669.         }
  670.         
  671.         if ((fromID == baseID) || (fromID == toID))
  672.             return somSelf;
  673.         if (versionList->IsAbove(fromID, toID) == kODFalse)
  674.             THROW(kODErrCannotCollapseDrafts);
  675.     
  676.         // from cannot have a ref count more than 1 if it is the top draft
  677.         // if from is not top draft, then we are not going to do anything to the draft
  678.         // and we need not worry about the ref count
  679.         
  680.         if (fromID == _fVersions->GetLatestDraftID())
  681.             if (from->GetRefCount(ev) > 1)
  682.                 THROW(kODErrOutstandingDraft);
  683.     
  684.         // Check for outstanding draft
  685.         
  686.         DraftListIterator draftList(_fDrafts);
  687.         draftList.Initialize();
  688.         CMDraft* draft = draftList.Last();
  689.         while (draft != kODNULL) {
  690.             ODDraftID draftID = draft->GetID(ev);
  691.             if ((versionList->IsBelow(draftID, fromID) != kODFalse) && 
  692.                 (versionList->IsAbove(draftID, toID) != kODFalse) &&
  693.                 (versionList->GetCurrentVersion(draftID) != kODTombstonedVersion))
  694.                 THROW(kODErrOutstandingDraft);
  695.             else
  696.                 draft = draftList.Previous();
  697.         }
  698.         // delete draftList;
  699.     
  700.         // Flush the from draft
  701.         
  702.         if ((from->GetPermissions(ev) == kODDPExclusiveWrite) &&
  703.             (from->NeedExternalizing(ev) != kODFalse))
  704.             THROW(kODErrNonEmptyDraft);
  705.         else if (from->IsChangedFromPrev(ev, versionList) != kODFalse)
  706.             THROW(kODErrNonEmptyDraft);
  707.         
  708.         if (from->IsNewDraft(ev) != kODFalse) {
  709.             revertIt = kODTrue;
  710. //            _fDrafts->Remove(from->GetID(ev));
  711.             ODDraftID id = from->GetID(ev);
  712.             from->Release(ev);
  713.             _fReleasedDrafts->Remove(id);
  714.             from->Abort(ev);
  715.             delete from;
  716.         }
  717.         else {
  718.             // so that the collapsed version list will be written out on close
  719.             _fContainer->SetDirtyFlag(ev, kODTrue);
  720.  
  721.             // Release the draft
  722.             
  723.             from->Release(ev);
  724.         }
  725.  
  726.         // CollapseDrafts on VersionList
  727.         
  728.         versionList->CollapseDrafts(fromID, toID);
  729.         
  730. #if !TestFlushContainer        
  731.         // Make the change persistent
  732.  
  733.         somSelf->ExternalizeVersionList(ev, kODFalse);
  734. #endif
  735.         
  736.         // If no change, then clear the dirty flag
  737.         
  738.         if (revertIt != kODFalse)
  739.             _fContainer->SetDirtyFlag(ev, kODFalse);
  740.  
  741.     CATCH_ALL
  742.     
  743.         somSelf->ReleaseVersionList(ev);
  744.         RERAISE;
  745.         
  746.     ENDTRY
  747.     
  748.     somSelf->ReleaseVersionList(ev);
  749.     
  750.     //if (releaseToDraft != kODFalse)
  751.     //    to->Release(ev);
  752.     
  753.     return somSelf;
  754.  
  755.     SOM_CATCH_ALL
  756.     SOM_ENDTRY
  757.     return somSelf;
  758. }
  759.  
  760. //------------------------------------------------------------------------------
  761. // CMDocument: AcquireDraft
  762. //------------------------------------------------------------------------------
  763.  
  764. SOM_Scope ODDraft*  SOMLINK CMDocumentAcquireDraft(CMDocument *somSelf, Environment *ev,
  765.         ODDraftPermissions perms,
  766.         ODDraftID id,
  767.         ODDraft* draft,
  768.         ODPositionCode posCode,
  769.         ODBoolean release)
  770. {
  771.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  772.     CMDocumentMethodDebug("CMDocument","CMDocumentAcquireDraft");
  773.  
  774.     SOM_TRY
  775.  
  776. #if ODDebug_Drafts
  777.     somPrintf("&&& AcquireDraft: id %d draft %x posCode %d release %d\n", id, draft, posCode, release);
  778. #endif
  779.  
  780.     VersionList*            versionList;
  781.     ODDraft*                newDraft;
  782.  
  783.     versionList = somSelf->TestAndGetVersionList(ev);
  784.     ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  785.         
  786.     TRY
  787.     
  788.         newDraft = somSelf->AcquireDraftGut(ev, versionList, perms, id, (CMDraft*) draft, posCode, release);
  789.         
  790.     CATCH_ALL
  791.     
  792.         somSelf->ReleaseVersionList(ev);
  793.         RERAISE;
  794.         
  795.     ENDTRY
  796.     
  797.     somSelf->ReleaseVersionList(ev);            
  798.  
  799. #if ODDebug_Drafts
  800.     somPrintf("&&& Exiting AcquireDraft\n");
  801. #endif
  802.         
  803.     return newDraft;
  804.  
  805.     SOM_CATCH_ALL
  806.     SOM_ENDTRY
  807.     return kODNULL;
  808. }
  809.  
  810. //------------------------------------------------------------------------------
  811. // CMDocument: Exists
  812. //------------------------------------------------------------------------------
  813.  
  814. SOM_Scope ODBoolean  SOMLINK CMDocumentExists(CMDocument *somSelf, Environment *ev,
  815.         ODDraftID id,
  816.         ODDraft* fromDraft,
  817.         ODPositionCode posCode)
  818. {
  819.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  820.     CMDocumentMethodDebug("CMDocument","CMDocumentExists");
  821.  
  822.     SOM_TRY
  823.  
  824.     ODBoolean    exists = kODFalse;
  825.     
  826.     if (id != 0) {
  827.         exists = _fVersions->Exists(id);
  828.     }
  829.     else if (fromDraft != kODNULL) {
  830.     
  831.         VersionList* versionList = somSelf->TestAndGetVersionList(ev);
  832.         ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  833.         
  834.         TRY
  835.             ODDraftID    fromDraftID = fromDraft->GetID(ev);
  836.     
  837.             switch (posCode) {
  838.                 case kODPosSame:
  839.                     exists = kODTrue;
  840.                 break;
  841.                 case kODPosFirstBelow:
  842.                 case kODPosLastBelow:
  843.                     exists = versionList->PreviousDraftExists(fromDraftID);
  844.                 break;
  845.                 case kODPosFirstAbove:
  846.                 case kODPosLastAbove:
  847.                     exists = versionList->NextDraftExists(fromDraftID);
  848.                 break;
  849.                 case kODPosUndefined:
  850.                 case kODPosAll:
  851.                 case kODPosFirstSib:
  852.                 case kODPosLastSib:
  853.                 case kODPosNextSib:
  854.                 case kODPosPrevSib:
  855.                 default:
  856.                     THROW(kODErrUnsupportedPosCode);
  857.                 break;
  858.             }
  859.         CATCH_ALL
  860.             somSelf->ReleaseVersionList(ev);
  861.             RERAISE;
  862.             
  863.         ENDTRY
  864.     }
  865.     else
  866.         THROW(kODErrInsufficientInfoInParams);
  867.     
  868.     return exists;
  869.  
  870.     SOM_CATCH_ALL
  871.     SOM_ENDTRY
  872.     return kODFalse;
  873. }
  874.  
  875. //------------------------------------------------------------------------------
  876. // CMDocument: AcquireBaseDraft
  877. //------------------------------------------------------------------------------
  878.  
  879. SOM_Scope ODDraft*  SOMLINK CMDocumentAcquireBaseDraft(CMDocument *somSelf, Environment *ev,
  880.         ODDraftPermissions perms)
  881. {
  882.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  883.     CMDocumentMethodDebug("CMDocument","CMDocumentAcquireBaseDraft");
  884.  
  885.     SOM_TRY
  886.  
  887.     CMContainer    cmContainer = _fContainer->GetCMContainer(ev);
  888.     ODSessionMustHaveCMAllocReserve(cmContainer);
  889.  
  890.     ODDraftID    baseDraftID;
  891.     ODDraft*    baseDraft;
  892.     CMProperty    versionListProp;
  893.     CMObject    versionListObj;
  894.     CMType        versionListType;
  895.     ODSByte    bogusData[1];
  896.     
  897.     TempCMValue versionList = somSelf->GetCMVersionList(ev);
  898.  
  899.     if ( !versionList ) {
  900.         if ((versionListProp = CMRegisterProperty(cmContainer, kODPropVersionList)) == kODNULL)
  901.             THROW(kODErrBentoInvalidProperty);
  902.         if ((versionListType = CMRegisterType(cmContainer, kODVersionList)) == kODNULL)
  903.             THROW(kODErrBentoInvalidType);
  904.         if ((versionListObj = CMNewObject(cmContainer)) == kODNULL)
  905.             THROW(kODErrBentoCannotNewObject);
  906.         versionList = CMNewValue(versionListObj, versionListProp, versionListType);
  907.  
  908.         if (versionList != kODNULL) {
  909.             CMWriteValueData(versionList, bogusData, 0, 0);
  910.         }
  911.         _fVersions = new(somSelf->GetHeap(ev)) VersionList();
  912.         _fVersions->Initialize();
  913.         
  914.         baseDraft = somSelf->CreateDraft(ev, kODNULL, kODFalse);
  915.     }
  916.     else {
  917.         baseDraftID = _fVersions->GetBaseDraftID();
  918.         baseDraft = somSelf->AcquireDraft(ev, perms, baseDraftID, kODNULL, kODPosUndefined, kODFalse);
  919.     }
  920.     
  921.     ODSessionRestoreCMAllocReserve(cmContainer);
  922.     return baseDraft;
  923.  
  924.     SOM_CATCH_ALL
  925.     SOM_ENDTRY
  926.     return kODNULL;
  927. }
  928.  
  929. //------------------------------------------------------------------------------
  930. // CMDocument: CreateDraft
  931. //------------------------------------------------------------------------------
  932.  
  933. SOM_Scope ODDraft*  SOMLINK CMDocumentCreateDraft(CMDocument *somSelf, Environment *ev,
  934.         ODDraft* below,
  935.         ODBoolean releaseBelow)
  936. {
  937.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  938.     CMDocumentMethodDebug("CMDocument","CMDocumentCreateDraft");
  939.  
  940.     SOM_TRY
  941.  
  942. #if ODDebug_Drafts
  943.     somPrintf("### Entering CreateDraft: below %x releaseBelow %d\n", below, releaseBelow);
  944.     PrintDrafts(ev, _fDrafts, "### Entering CreateDraft");
  945.     somSelf->GetVersionList(ev)->Print(">>> Entering CreateDraft");
  946. #endif
  947.     
  948.     ODDraftID                    prevDraftID;
  949.     CMDraft*                    newDraft;
  950.     VersionList*                versionList;
  951.     
  952.     versionList = somSelf->TestAndGetVersionList(ev);
  953.     ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  954.         
  955.     TRY
  956.  
  957.         prevDraftID = versionList->GetLatestDraftID();    
  958.         if ((prevDraftID != 0) &&
  959.             (below != kODNULL) &&
  960.             (prevDraftID != below->GetID(ev)))
  961.             THROW(kODErrInvalidBelowDraft);
  962.     
  963.         if (releaseBelow != kODFalse) {
  964.             if (below != kODNULL) {
  965.                 below->Release(ev);
  966.             }
  967.         }
  968.         else {
  969.             if ((below != kODNULL) && (below->GetPermissions(ev) == kODDPExclusiveWrite)) {
  970.                 THROW(kODErrInvalidPermissions);
  971.             }
  972.         }
  973.  
  974.         newDraft = NewCMDraft(somSelf->GetHeap(ev));
  975.         newDraft->InitDraft(ev, somSelf, kODNULL, kODDPExclusiveWrite);
  976.     
  977.         _fDrafts->Add(newDraft->GetID(ev), newDraft);
  978.  
  979.     CATCH_ALL
  980.     
  981.         somSelf->ReleaseVersionList(ev);
  982.         RERAISE;
  983.         
  984.     ENDTRY
  985.     
  986.     somSelf->ReleaseVersionList(ev);            
  987.     
  988. #if ODDebug_Drafts
  989.     PrintDrafts(ev, _fDrafts, "### Exiting CreateDraft");
  990.     somSelf->GetVersionList(ev)->Print(">>> Exiting CreateDraft");
  991. #endif
  992.         
  993.     return newDraft;
  994.  
  995.     SOM_CATCH_ALL
  996.     SOM_ENDTRY
  997.     return kODNULL;
  998. }
  999.  
  1000. //------------------------------------------------------------------------------
  1001. // CMDocument: SaveToAPrevDraft
  1002. //------------------------------------------------------------------------------
  1003.  
  1004. SOM_Scope void  SOMLINK CMDocumentSaveToAPrevDraft(CMDocument *somSelf, Environment *ev,
  1005.         ODDraft* fromDraft,
  1006.         ODDraft* toDraft)
  1007. {
  1008.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  1009.     CMDocumentMethodDebug("CMDocument","CMDocumentSaveToAPrevDraft");
  1010.  
  1011.     SOM_TRY
  1012.  
  1013.     CMDraft*        from = (CMDraft*) fromDraft;
  1014.     ODDraftID        fromID = from->GetID(ev);
  1015.     ODDraftID        toID;
  1016.     VersionList*    versionList;
  1017.     ODBoolean        notTopDraft = kODFalse;
  1018.     ODTime            now;
  1019.  
  1020.     versionList = somSelf->TestAndGetVersionList(ev);
  1021.     ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  1022.         
  1023.     TRY
  1024.  
  1025.         if (toDraft == kODNULL) {
  1026.             toID = _fVersions->GetPreviousDraftID(fromID);
  1027.         }
  1028.         else {
  1029.             toID = toDraft->GetID(ev);
  1030.         }
  1031.             
  1032.         if (fromID == toID)
  1033.             return;
  1034.             
  1035.         if ((_fVersions->Exists(fromID) == kODFalse) ||
  1036.             (_fVersions->Exists(toID) == kODFalse) ||
  1037.             (versionList->IsAbove(fromID, toID) == kODFalse))
  1038.             THROW(kODErrDraftDoesNotExist);
  1039.         
  1040.         // Check to see whether we have any outstanding ODDraft associated
  1041.         //    with this document.
  1042.         
  1043.         DraftListIterator draftList(_fDrafts);
  1044.         draftList.Initialize();
  1045.         
  1046.         CMDraft* draft = draftList.Last();
  1047.         while (draft != kODNULL) {
  1048.             ODDraftID    id = draft->GetID(ev);
  1049.             if ((versionList->IsBelow(id, fromID) != kODFalse) && 
  1050.                 (versionList->IsAbove(id, toID) != kODFalse) &&
  1051.                 (versionList->GetCurrentVersion(id) != kODTombstonedVersion))
  1052.                 THROW(kODErrOutstandingDraft);
  1053.             else
  1054.                 draft = draftList.Previous();
  1055.         }
  1056.         // delete draftList;
  1057.     
  1058.         // SaveToAPrevDraft on VersionList
  1059.         
  1060.         _fVersions->SaveToAPrevDraft(fromID, toID);
  1061.         
  1062.         if (fromID != _fVersions->GetLatestDraftID())
  1063.             notTopDraft = kODTrue;
  1064.  
  1065. #if !TestFlushContainer
  1066.         // Make the version list change persistent
  1067.         
  1068.         somSelf->ExternalizeVersionList(ev, kODFalse);
  1069. #endif
  1070.         
  1071.         // Write out if it is an exclusive write container
  1072.         if (notTopDraft == kODFalse)    
  1073.             from->Close(ev);
  1074.  
  1075.         CMContainer    cmContainer = _fContainer->GetCMContainer(ev);
  1076.         
  1077. #if TestFlushContainer
  1078.  
  1079.         // Make the version list change persistent
  1080.         
  1081.         somSelf->ExternalizeVersionList(ev, notTopDraft);
  1082.         
  1083.         ODSessionMustHaveCMAllocReserve(cmContainer);
  1084.         CMTakeSnapShot(cmContainer, kODFalse);
  1085. #endif
  1086.         time(&now);
  1087.         ASSERTM(sizeof(ODTime) == sizeof(time_t), kODErrAssertionFailed, "ODTime not same as time_t.");
  1088.  
  1089.         _fContainer->SetModDate(ev, now); 
  1090.  
  1091.         if (notTopDraft == kODFalse) { // if we have close it before we open it again
  1092.             from->Open(ev);
  1093.             
  1094.             from->SetChangedFromPrevFlag(ev, kODFalse);
  1095.         }        
  1096.         
  1097.         // Release to draft if necessary
  1098.         
  1099.         if (toDraft != kODNULL) {
  1100.             ((CMDraft*) toDraft)->Close(ev);
  1101.             ((CMDraft*) toDraft)->Open(ev);
  1102.         }
  1103.         ODSessionMustHaveCMAllocReserve(cmContainer);
  1104.  
  1105.     CATCH_ALL
  1106.     
  1107.         somSelf->ReleaseVersionList(ev);
  1108.         RERAISE;
  1109.         
  1110.     ENDTRY
  1111.     
  1112.     somSelf->ReleaseVersionList(ev);            
  1113.  
  1114.     SOM_CATCH_ALL
  1115.     SOM_ENDTRY
  1116. }
  1117.  
  1118. //------------------------------------------------------------------------------
  1119. // CMDocument: SetBaseDraftFromForeignDraft
  1120. //------------------------------------------------------------------------------
  1121.  
  1122. SOM_Scope void  SOMLINK CMDocumentSetBaseDraftFromForeignDraft(CMDocument *somSelf, Environment *ev,
  1123.         ODDraft* draft)
  1124. {
  1125.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  1126.     CMDocumentMethodDebug("CMDocument","CMDocumentSetBaseDraftFromForeignDraft");
  1127.  
  1128.     SOM_TRY
  1129.  
  1130.     TempODDraft baseDraft = somSelf->AcquireBaseDraft(ev, kODDPExclusiveWrite);
  1131.     
  1132.     {
  1133.         TempODStorageUnit fromDraftProperties = draft->AcquireDraftProperties(ev);
  1134.         TempODStorageUnit toDraftProperties = baseDraft->AcquireDraftProperties(ev);
  1135.         
  1136.         ODDraftKey key = draft->BeginClone(ev, baseDraft, kODNULL, kODCloneAll); 
  1137.         TRY
  1138.             draft->Clone(ev, key, fromDraftProperties->GetID(ev), toDraftProperties->GetID(ev), kODNULL);
  1139.             draft->EndClone(ev, key );
  1140.         CATCH_ALL
  1141.             draft->AbortClone(ev, key);
  1142.         ENDTRY
  1143.         
  1144.     }
  1145.     baseDraft->Externalize(ev);
  1146.  
  1147.     SOM_CATCH_ALL
  1148.     SOM_ENDTRY
  1149. }
  1150.  
  1151. //------------------------------------------------------------------------------
  1152. // CMDocument: InitDocument
  1153. //------------------------------------------------------------------------------
  1154.  
  1155. SOM_Scope void  SOMLINK CMDocumentInitDocument(CMDocument *somSelf, Environment *ev,
  1156.         ODContainer* container,
  1157.         ODDocumentID id)
  1158. {
  1159.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  1160.     CMDocumentMethodDebug("CMDocument","CMDocumentInitDocument");
  1161.     
  1162.     SOM_TRY
  1163.         
  1164.     /* Moved from somInit. SOM itself sets fields to zero
  1165.     _fContainer = (ODBentoContainer*) kODNULL;
  1166.     _fID = 0;
  1167.     _fDrafts = kODNULL;
  1168.     _fReleasedDrafts = kODNULL;
  1169.     
  1170.     _fVersions = kODNULL;
  1171.     _fVersionListSemaphore = 0;
  1172.     
  1173.     _fHeap = kDefaultHeapID;
  1174.     */
  1175.     
  1176.     somSelf->InitRefCntObject(ev);
  1177.     
  1178.     _fContainer = (ODBentoContainer*) container;
  1179.     if (_fContainer == kODNULL)
  1180.         THROW(kODErrIllegalNullContainerInput);
  1181.  
  1182.     _fID = id;
  1183.         
  1184.     _fDrafts = new(somSelf->GetHeap(ev)) DraftList;
  1185.     _fDrafts->Initialize();
  1186.     
  1187.     _fReleasedDrafts = new(somSelf->GetHeap(ev)) DraftList;
  1188.     _fReleasedDrafts->Initialize();
  1189.     
  1190.     somSelf->InternalizeVersionList(ev);
  1191.  
  1192.     if (_fVersions == kODNULL) {
  1193.     
  1194.         // If we get here, that means we have a new document.
  1195.         // A new document makes a container dirty by definition. Therefore,
  1196.         // we have to set the dirty flag.
  1197.     
  1198.         _fContainer->SetDirtyFlag(ev, kODTrue);
  1199.         
  1200.         // We are not creating a VersionList yet because the user may
  1201.         // just close the document without creating any version.
  1202.     
  1203.     }
  1204.     
  1205.     _fHeap = _fContainer->GetHeap(ev);
  1206.     
  1207.     SOM_CATCH_ALL
  1208.     SOM_ENDTRY
  1209. }
  1210.  
  1211. //------------------------------------------------------------------------------
  1212. // CMDocument: ReleaseDraft
  1213. //------------------------------------------------------------------------------
  1214.  
  1215. SOM_Scope ODDocument*  SOMLINK CMDocumentReleaseDraft(CMDocument *somSelf, Environment *ev,
  1216.         ODDraft* draftToRelease)
  1217. {
  1218.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  1219.     CMDocumentMethodDebug("CMDocument","CMDocumentReleaseDraft");
  1220.  
  1221. #if ODDebug_Drafts
  1222.     somPrintf("@@@ ReleaseDraft: draft %x id %d\n", draftToRelease, draftToRelease->GetID(ev));
  1223.     PrintHeapInfo();
  1224. #endif
  1225.  
  1226.     CMDraft*        draft = (CMDraft*) draftToRelease;
  1227.     ODDraftID        draftID = draft->GetID(ev);
  1228.     
  1229.     SOM_TRY
  1230.     if ((draft = _fDrafts->Get(draftID)) != kODNULL) {
  1231.         _fDrafts->Remove(draftID);
  1232.         _fReleasedDrafts->Add(draftID, draft);
  1233.         if (draft->GetPermissions(ev) == kODDPExclusiveWrite) {
  1234.             if (draft->NeedExternalizing(ev) != kODFalse) {
  1235.                 if (draft->ChangedFromPrev(ev) != kODFalse)
  1236.                     _fContainer->SetDirtyFlag(ev, kODTrue);
  1237.                 draft->Close(ev);
  1238. #if !TestFlushContainer
  1239.                 somSelf->ExternalizeVersionList(ev, kODFalse);
  1240. #endif
  1241.             }
  1242.             else if (draft->IsNewDraft(ev) != kODFalse) {
  1243.                 if (draft->GetID(ev) == _fVersions->GetBaseDraftID()) {
  1244.                     if (draft->ChangedFromPrev(ev) != kODFalse)
  1245.                         draft->RemoveChanges(ev);
  1246.                     draft->Close(ev);
  1247. #if !TestFlushContainer
  1248.                     somSelf->ExternalizeVersionList(ev, kODFalse);
  1249. #endif
  1250.                 }
  1251.                 else
  1252.                     draft->Abort(ev);
  1253.             }
  1254.             else
  1255.                 draft->Abort(ev);
  1256.         }
  1257.         else
  1258.             draft->Close(ev);
  1259.     }
  1260.     else
  1261.         THROW(kODErrDraftDoesNotExist);
  1262.     SOM_CATCH_ALL
  1263.     SOM_ENDTRY
  1264.  
  1265. #if ODDebug_Drafts
  1266.     somPrintf("@@@ ReleaseDraft: Done.\n");
  1267.     PrintHeapInfo();
  1268. #endif
  1269.         
  1270.     return somSelf;
  1271. }
  1272.  
  1273. //------------------------------------------------------------------------------
  1274. // CMDocument: InternalizeVersionList
  1275. //------------------------------------------------------------------------------
  1276.  
  1277. SOM_Scope void  SOMLINK CMDocumentInternalizeVersionList(CMDocument *somSelf, Environment *ev)
  1278. {
  1279.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  1280.     CMDocumentMethodDebug("CMDocument","CMDocumentInternalizeVersionList");
  1281.  
  1282.     SOM_TRY
  1283.  
  1284.     ODPtr            tmpBuffer;
  1285.     ODULong        versionListSize;
  1286.     TempCMValue versionList = somSelf->GetCMVersionList(ev);
  1287.     
  1288.     if (versionList == kODNULL)
  1289.         return;
  1290.  
  1291.     CMContainer    cmContainer = _fContainer->GetCMContainer(ev);
  1292.     ODSessionMustHaveCMAllocReserve(cmContainer);
  1293.  
  1294.     versionListSize = CMGetValueSize(versionList);
  1295.     
  1296.     tmpBuffer = ODNewPtr(versionListSize, somSelf->GetHeap(ev));
  1297.     
  1298.     CMReadValueData(versionList, tmpBuffer, 0, versionListSize);
  1299.     
  1300.     if (_fVersions == kODNULL) {
  1301.         _fVersions = new(somSelf->GetHeap(ev)) VersionList;
  1302.         _fVersions->Initialize(tmpBuffer, versionListSize);
  1303.     }
  1304.     else {
  1305.         _fVersions->Reinitialize(tmpBuffer, versionListSize);
  1306.     }
  1307.     
  1308.     ODDisposePtr(tmpBuffer);
  1309.  
  1310.     ODSessionRestoreCMAllocReserve(cmContainer);
  1311.     
  1312. #if ODDebug_Drafts
  1313.     _fVersions->Print("Internalized VersionList");
  1314. #endif
  1315.  
  1316.     SOM_CATCH_ALL
  1317.     SOM_ENDTRY
  1318. }
  1319.  
  1320. //------------------------------------------------------------------------------
  1321. // CMDocument: ExternalizeVersionList
  1322. //------------------------------------------------------------------------------
  1323.  
  1324. extern void ODBentoFatalError(ODBoolean allowSuppress); // SessHdr.cpp
  1325.  
  1326. SOM_Scope void  SOMLINK CMDocumentExternalizeVersionList(CMDocument *somSelf, Environment *ev, ODBoolean ignoreTopDraft)
  1327. {
  1328.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  1329.     CMDocumentMethodDebug("CMDocument","CMDocumentExternalizeVersionList");
  1330.  
  1331.     SOM_TRY
  1332.  
  1333.     ODPtr            tmpBuffer;
  1334.     ODULong        tmpBufferSize;
  1335.     TempCMValue versionList = somSelf->GetCMVersionList(ev);
  1336.  
  1337.     if (versionList == kODNULL)
  1338.         THROW(kODErrNoVersionList);
  1339.  
  1340.     if (_fVersions != kODNULL) {
  1341.         CMContainer    cmContainer = _fContainer->GetCMContainer(ev);
  1342.         ODSessionMustHaveCMAllocReserve(cmContainer);
  1343.  
  1344. #if ODDebug_Drafts
  1345.     _fVersions->Print("Externalizing VersionList");
  1346. #endif
  1347.         CMSize oldSize = CMGetValueSize(versionList);
  1348.  
  1349.         _fVersions->ExportTo(&tmpBuffer, &tmpBufferSize, ignoreTopDraft);
  1350.  
  1351.         // Write out the new version list.
  1352.         CMInsertValueData(versionList, tmpBuffer, 0, tmpBufferSize);
  1353.                 
  1354.         // Delete old version list.
  1355.         CMDeleteValueData(versionList, tmpBufferSize, oldSize);
  1356.         
  1357.         // Instead of deleting the data in the current value, let's delete the value, and
  1358.         // add again anew.
  1359.         
  1360.         /*
  1361.         ODULong useCount = CMGetValueUseCount(versionList);
  1362.         if ( useCount == 1 )
  1363.         {
  1364.             versionList.DontRelease();
  1365.             CMDeleteValue(versionList);
  1366.                         
  1367.             CMProperty versionListProp = CMRegisterProperty(cmContainer, kODPropVersionList);
  1368.             if ( !versionListProp )
  1369.                 THROW(kODErrBentoInvalidProperty);
  1370.  
  1371.             CMType versionListType = CMRegisterType(cmContainer, kODVersionList);
  1372.             if ( !versionListType )
  1373.                 THROW(kODErrBentoInvalidType);
  1374.     
  1375.             CMObject versionListObj = CMGetNextObjectWithProperty(cmContainer, kODNULL, versionListProp);
  1376.             if ( versionListObj ) {
  1377.                 versionList = CMNewValue(versionListObj, versionListProp, versionListType);
  1378.                 if ( versionList )
  1379.                     CMWriteValueData(versionList, tmpBuffer, 0, tmpBufferSize);
  1380.             }
  1381.             else {
  1382.                 WARN("cant %.64s", (versionListObj)? "make version list value" : "find version list property");
  1383.                 THROW( kODErrInvalidVersionListUseCount );
  1384.             }
  1385.         }
  1386.         else {
  1387.             WARN("version list use count is not one: %lu", (unsigned long) useCount);
  1388.             THROW( kODErrInvalidVersionListUseCount );
  1389.         }
  1390.         */
  1391.         
  1392.         ODDisposePtr(tmpBuffer);
  1393.         ODSessionRestoreCMAllocReserve(cmContainer);
  1394.         
  1395.     }
  1396.  
  1397.     SOM_CATCH_ALL
  1398.     
  1399.     ODBentoFatalError(/*allowSuppress*/ kODTrue);
  1400.     
  1401.     SOM_ENDTRY
  1402. }
  1403.  
  1404. //------------------------------------------------------------------------------
  1405. // CMDocument: Reopen
  1406. //------------------------------------------------------------------------------
  1407.  
  1408. SOM_Scope void  SOMLINK CMDocumentReopen(CMDocument *somSelf, Environment *ev)
  1409. {
  1410.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  1411.     CMDocumentMethodDebug("CMDocument","Reopen");
  1412.  
  1413.     SOM_TRY
  1414.  
  1415.     DraftListIterator iter(_fDrafts);
  1416.     CMDraft*                draft;
  1417.  
  1418.     iter.Initialize();
  1419.     draft = iter.Last();
  1420.     while (draft != kODNULL) {
  1421.         draft->Open(ev);
  1422.         draft = iter.Previous();
  1423.     }
  1424.     // delete iter;
  1425.  
  1426.     SOM_CATCH_ALL
  1427.     SOM_ENDTRY
  1428. }
  1429.  
  1430. //------------------------------------------------------------------------------
  1431. // CMDocument: GetVersionList
  1432. //------------------------------------------------------------------------------
  1433.  
  1434. SOM_Scope VersionList*  SOMLINK CMDocumentGetVersionList(CMDocument *somSelf, Environment *ev)
  1435. {
  1436.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  1437.     CMDocumentMethodDebug("CMDocument","GetVersionList");
  1438.  
  1439.     return _fVersions;
  1440. }
  1441.  
  1442. //------------------------------------------------------------------------------
  1443. // CMDocument: TestAndGetVersionList
  1444. //------------------------------------------------------------------------------
  1445.  
  1446. SOM_Scope VersionList*  SOMLINK CMDocumentTestAndGetVersionList(CMDocument *somSelf, Environment *ev)
  1447. {
  1448.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  1449.     CMDocumentMethodDebug("CMDocument","TestAndGetVersionList");
  1450.  
  1451.     SOM_TRY
  1452.  
  1453.     DisableInterrupt();
  1454.  
  1455.     if (_fVersionListSemaphore > 0) {
  1456. //        if same thread,
  1457.             _fVersionListSemaphore++;
  1458. //         else {
  1459. //            EnableInterrupt();
  1460. //            THROW(kODErrVersionListUnavailable);
  1461. //
  1462.     }
  1463.     else {
  1464. //        store the thread
  1465.         _fVersionListSemaphore++;
  1466.     }
  1467.             
  1468.     EnableInterrupt();
  1469.     
  1470.     return _fVersions;
  1471.  
  1472.     SOM_CATCH_ALL
  1473.     SOM_ENDTRY
  1474.     return kODNULL;
  1475. }
  1476.  
  1477. //------------------------------------------------------------------------------
  1478. // CMDocument: ReleaseVersionList
  1479. //------------------------------------------------------------------------------
  1480.  
  1481. SOM_Scope void  SOMLINK CMDocumentReleaseVersionList(CMDocument *somSelf, Environment *ev)
  1482. {
  1483.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  1484.     CMDocumentMethodDebug("CMDocument","ReleaseVersionList");
  1485.  
  1486.     SOM_TRY
  1487.  
  1488.     DisableInterrupt();
  1489.     
  1490.     if (_fVersionListSemaphore > 0) {
  1491. //        if (same thread) {
  1492.             --_fVersionListSemaphore;
  1493.             EnableInterrupt();    
  1494. //        }
  1495. //        else {
  1496. //            EnableInterrupt();
  1497. //            THROW(kODErrVersionListUnavailable);
  1498. //        }
  1499.     }
  1500.     else {
  1501.         EnableInterrupt();    
  1502.         THROW(kODErrSemaphoreReleased);
  1503.     }
  1504.  
  1505.     SOM_CATCH_ALL
  1506.     SOM_ENDTRY
  1507. }
  1508.  
  1509. //------------------------------------------------------------------------------
  1510. // CMDocument: GetHeap
  1511. //------------------------------------------------------------------------------
  1512.  
  1513. SOM_Scope ODMemoryHeapID  SOMLINK CMDocumentGetHeap(CMDocument *somSelf, Environment *ev)
  1514. {
  1515.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  1516.     CMDocumentMethodDebug("CMDocument","GetHeap");
  1517.  
  1518.     return _fHeap;
  1519. }
  1520.  
  1521. //------------------------------------------------------------------------------
  1522. // AcquireDocumentPropertiesObject
  1523. //------------------------------------------------------------------------------
  1524.  
  1525. static CMObject AcquireDocumentPropertiesObject(CMContainer container)
  1526. {
  1527.     CMObject        documentPropertiesObject;
  1528.     CMProperty        docPropertiesProp;
  1529.     CMType            docPropertiesType;
  1530.     CMValue            value;
  1531.  
  1532.     // CMContainer    cmContainer = _fContainer->GetCMContainer(ev);
  1533.     // ODSessionMustHaveCMAllocReserve(cmContainer);
  1534.     // This is a static function which is only called by functions that
  1535.     // have already called ODSessionMustHaveCMAllocReserve().
  1536.  
  1537.     if ((docPropertiesProp = CMRegisterProperty(container, kODDocumentProperties)) == kODNULL)
  1538.         THROW(kODErrBentoInvalidProperty);
  1539.     documentPropertiesObject = CMGetNextObjectWithProperty(container, kODNULL, docPropertiesProp);
  1540.     
  1541.     if (documentPropertiesObject == kODNULL) {
  1542.  
  1543.         CMContainerModeFlags    openMode;
  1544.         
  1545.         CMGetContainerInfo(container, kODNULL, kODNULL, kODNULL, kODNULL, &openMode);
  1546.         if (openMode == kCMReading)
  1547.             return kODNULL;
  1548.         
  1549.         if ((docPropertiesType = CMRegisterType(container, kODValue)) == kODNULL)
  1550.             THROW(kODErrBentoInvalidProperty);
  1551.  
  1552.         if ((documentPropertiesObject = CMNewObject(container)) == kODNULL)
  1553.             THROW(kODErrBentoCannotNewObject);
  1554.             
  1555.         if ((value = CMNewValue(documentPropertiesObject, docPropertiesProp, docPropertiesType)) == kODNULL)
  1556.             THROW(kODErrBentoCannotNewValue);
  1557.             
  1558.         CMWriteValueData(value, "", 0, 0);
  1559.     }
  1560.     // ODSessionRestoreCMAllocReserve(cmContainer);
  1561.     
  1562.     return documentPropertiesObject;
  1563. }
  1564.  
  1565. //------------------------------------------------------------------------------
  1566. // NewCMDraft
  1567. //------------------------------------------------------------------------------
  1568.  
  1569. static CMDraft* NewCMDraft(ODMemoryHeapID heapID)
  1570. {
  1571.     SOMClass*    cmDraftClass = somNewClassReference(CMDraft);
  1572.     THROW_IF_NULL( cmDraftClass );
  1573.     ODULong        size = cmDraftClass->somGetInstanceSize();
  1574.     ODPtr        buffer = ODNewPtr(size, heapID);
  1575.     CMDraft*    cmDraft = (CMDraft*) cmDraftClass->somRenew(buffer);
  1576.     somReleaseClassReference ( cmDraftClass );
  1577.     
  1578.     return cmDraft;
  1579. }
  1580.  
  1581. #if ODDebug_Drafts
  1582.  
  1583. //------------------------------------------------------------------------------
  1584. // PrintDrafts
  1585. //------------------------------------------------------------------------------
  1586.  
  1587. static void PrintDrafts(Environment* ev, DraftList* drafts, char* string)
  1588. {
  1589. /*
  1590.     DraftListIterator*    draftList = new DraftListIterator(drafts);
  1591.     draftList->Initialize();
  1592.     for (CMDraft* draft = draftList->Last(); draftList->IsNotComplete(); draft = draftList->Previous()) {
  1593.         somPrintf("%s: draft %x %d refCount %d\n", string, draft, draft->GetID(ev), draft->GetRefCount(ev));
  1594.     }
  1595.     delete draftList;
  1596. */
  1597. }
  1598.  
  1599. //------------------------------------------------------------------------------
  1600. // PrintHeapInfo
  1601. //------------------------------------------------------------------------------
  1602.  
  1603. static void PrintHeapInfo()
  1604. {
  1605. /*
  1606.     MemHeap*    heapID = 0;
  1607.     const char *name;
  1608.     size_t allocated;
  1609.     size_t free;
  1610.     size_t nBlocks;
  1611.     size_t nObjects;
  1612.     MMGetHeapInfo(heapID,
  1613.                     &name,
  1614.                     &allocated,
  1615.                     &free,
  1616.                     &nBlocks,
  1617.                     &nObjects );
  1618.     somPrintf("Heap: allocated %d, free %d, nBlocks %d, nObjects %d\n", allocated, free, nBlocks, nObjects);
  1619. */
  1620. }
  1621.  
  1622.  
  1623. #endif
  1624.  
  1625.  
  1626.